package it.aekidna.cleverplatypus.workflow
{
	import as3reflect.ClassUtils;
	
	import flash.events.EventDispatcher;
	import flash.net.registerClassAlias;
	import flash.utils.getQualifiedClassName;
	
	import it.aekidna.cleverplatypus.mediator.MetadataUtil;
	import it.aekidna.cleverplatypus.utils.IAutowirable;
	
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.ObjectUtil;

	[Event(
		name="started",
		type="it.aekidna.cleverplatypus.workflow.WorkflowEvent")]
	[Event(
    	name="warning",
    	type="it.aekidna.cleverplatypus.workflow.WorkflowEvent")]
	[Event(
		name="fault",
		type="it.aekidna.cleverplatypus.workflow.WorkflowEvent")]
	[Event(
		name="completed",
		type="it.aekidna.cleverplatypus.workflow.WorkflowEvent")]

	public class AbstractWorkflowTask 
		extends EventDispatcher 
		implements IWorkflowTask, IAutowirable
	{
		private static const LOGGER : ILogger = 
			Log.getLogger( getQualifiedClassName( Workflow ).replace(/:+/g, "." ) );
			
		public static const ABORT : String = "abort";
		public static const WARN : String = "warn";
		public static const IGNORE : String = "ignore";
		
		private var _listeners : Object = {};
		
		protected var _parent : IWorkflowTask;
		protected var _name : String= "unnamed";
		protected var _enabled : Boolean = true;
		protected var _failurePolicy : String = ABORT;
		
		public function AbstractWorkflowTask()
		{
			super(this);
        try
        {
        	MetadataUtil.autowireObject( this );
        }
        catch( e : Error )
        {
        	LOGGER.warn( "Workflow task {0} cannot be autowired because " + 
        			"no default context has been set for MetadataUtil", name );
        }
		}

		public function get name():String
		{
			return _name;
		}
		
		public function set name(inName:String):void
		{
			_name = inName;
		}
		
		public function get parent() : IWorkflowTask
		{
			return _parent;
		}
		
		public function set parent( inParent : IWorkflowTask ) : void
		{
			_parent = inParent;
		}

		[Inspectable(defaultValue="true", type="Boolean")]
		public function get enabled() : Boolean
		{
			return _enabled;
		}
		
		public function set enabled( inEnabled : Boolean ) : void
		{
			_enabled = inEnabled;
		}

		[Inspectable(defaultValue="abort", enumeration="abort,warn,ignore")]
		public function get failurePolicy() : String
		{
			return _failurePolicy;
		}
		
		public function set failurePolicy( inPolicy : String ) : void
		{
			if( inPolicy != ABORT && inPolicy != IGNORE && inPolicy != WARN )
			{
				throw new Error( 
					"Workflow 'failurePolicy' property can only be either 'abort' or 'warn' or 'ignore': " +
					"found '" + inPolicy + "'" );
			}
			_failurePolicy = inPolicy;
		}
		
		public function cleanUp():void
		{
		}
		
		virtual public function begin():void
		{
		}
		
		protected function complete() : void
		{
			LOGGER.debug( 
				"Task '{0}' completed", name );
			dispatchEvent( new WorkflowEvent( WorkflowEvent.COMPLETED ) );
		}
		
		protected function completeWithWarning( inWarning : String ) : void
		{
			dispatchEvent( new WorkflowEvent( WorkflowEvent.WARNING, inWarning ) );
		}
		
		protected function fail( inFailureDescription : String ) : void
		{
			dispatchEvent( new WorkflowEvent( WorkflowEvent.FAULT ) );
		}
		
	}
}